﻿using System;
using System.Collections.Generic;
using System.Text;
using Sinacor.Infra.Service.Data;
using System.Data.Common;
using System.Data;
using Sinacor.Servico.Bovespa.Comum.ResourceAccess;
using Sinacor.Infra.Service.Security.Authorization;
using System.Globalization;

namespace Sinacor.Servico.Bovespa.Ordens.ResourceAccess
{
    public class LoteOrdem : BaseResourceAccess
    {
        public LoteOrdem()
            : base(AuthorizationContext.Current.CompanyId)
        {

        }
        /// Data:14/07/2008
        /// Autor:Marcelo Barucci
        /// Obs:
        /// Busca por todos ou nenhum campo da tabela TORDISCONJ
        public List<BusinessEntity.LoteOrdem> ConsultarOrdemLote(BusinessEntity.LoteOrdem request)
        {
            List<BusinessEntity.LoteOrdem> response = new List<BusinessEntity.LoteOrdem>();
            IDataReader reader;
            DbCommand dbCommand;

            #region Monta a string SQL
            StringBuilder sql = new StringBuilder();

            sql.Append("select ");
            sql.Append("DT_DATORD, ");
            sql.Append("NR_SEQORD, ");
            sql.Append("NR_SUBSEQ, ");
            sql.Append("DT_PREGAO, ");
            sql.Append("NR_CONJUNTO ");
            sql.Append("from TORDISCONJ ");
            sql.Append("where 0=0");
            #endregion Monta a string SQL

            #region Adiciona os parametros de acordo com os valores passados no objeto

            if (request.NumeroConjunto.HasValue)
            {
                sql.Append(" AND TORDISCONJ.DT_DATORD = :dataordem ");
            }
            if (request.NumeroSequenciaOrdem.HasValue)
            {
                sql.Append(" AND TORDISCONJ.NR_SEQORD = :numerosequenciaordem ");
            }
            if (request.NumeroSubSequenciaOrdem.HasValue)
            {
                sql.Append(" AND TORDISCONJ.NR_SUBSEQ = :numerosubsequenciaordem ");
            }
            if (request.DataOrdem.HasValue)
            {
                sql.Append(" AND TORDISCONJ.DT_PREGAO = :datapregao ");
            }
            if (request.DataPregao.HasValue)
            {
                sql.Append(" AND TORDISCONJ.NR_CONJUNTO = :numeroconjunto ");
            }

            dbCommand = this.DataBase.GetSqlStringCommand(sql.ToString());

            if (request.NumeroConjunto.HasValue)
            {
                this.DataBase.AddInParameter(dbCommand, "dataordem", DbType.Date, request.DataOrdem.Value);
            }
            if (request.NumeroSequenciaOrdem.HasValue)
            {
                this.DataBase.AddInParameter(dbCommand, "numerosequenciaordem", DbType.Int32, request.NumeroSequenciaOrdem.Value);
            }
            if (request.NumeroSubSequenciaOrdem.HasValue)
            {
                this.DataBase.AddInParameter(dbCommand, "numerosubsequenciaordem", DbType.Int32, request.NumeroSubSequenciaOrdem.Value);
            }
            if (request.DataOrdem.HasValue)
            {
                this.DataBase.AddInParameter(dbCommand, "datapregao", DbType.Date, request.DataPregao.Value);
            }
            if (request.DataPregao.HasValue)
            {
                this.DataBase.AddInParameter(dbCommand, "numeroconjunto", DbType.Int32, request.NumeroConjunto.Value);
            }
            #endregion Adiciona os parametros de acordo com os valores passados no objeto

            reader = this.DataBase.ExecuteReader(dbCommand);

            #region Mapeia o Objeto e adiciona na Lista
            while (reader.Read())
            {
                BusinessEntity.LoteOrdem loteOrdem = new BusinessEntity.LoteOrdem();
                loteOrdem.NumeroConjunto = Convert.ToInt32(reader["NR_CONJUNTO"].ToString());
                loteOrdem.NumeroSequenciaOrdem = Convert.ToInt32(reader["NR_SEQORD"].ToString());
                loteOrdem.NumeroSubSequenciaOrdem = Convert.ToInt32(reader["NR_SUBSEQ"].ToString());
                loteOrdem.DataOrdem = Convert.ToDateTime(reader["DT_DATORD"].ToString());
                loteOrdem.DataPregao = Convert.ToDateTime(reader["DT_PREGAO"].ToString());
                response.Add(loteOrdem);
            }
            #endregion Mapeia o Objeto e adiciona na Lista

            reader.Close();
            return response;
        }

        ///<summary>
        ///Método responsavel por criar um novo lote para ordens que já estejam em um lote (NumeroConjunto > 0).
        ///</summary>
        ///<returns>número do novo lote recém-criado</returns>
        // Marcelo Barucci  11/07/2008        Criacao
        // WAbreu.7COMm     02/10/2008 11:00  Retorna numero do novo lote
        public Int32 CriarLoteOrdemComLote(BusinessEntity.LoteOrdem request)
        {
            DbCommand dbCommand;
            DbParameter parameter;
            StringBuilder sql = new StringBuilder();

            /*
            PROCEDURE NOVO_CONJ ( P_DT_DATORD VARCHAR2, P_NR_SEQORD VARCHAR2, P_NR_SUBSEQ VARCHAR2,
                         P_DT_PREGAO VARCHAR2, P_CJO_ANT   VARCHAR2, P_CJO   OUT NUMBER ) IS
            */

            sql.Append("BEGIN ");
            sql.Append("ATUA_CONJORD.NOVO_CONJ(:P_DT_DATORD,:P_NR_SEQORD,:P_NR_SUBSEQ,:P_DT_PREGAO,:P_CJO_ANT, :RET);");
            sql.Append("END; ");
            dbCommand = this.DataBase.GetSqlStringCommand(sql.ToString());

            #region Cria os Parametros a Adiciona ao Command
            parameter = dbCommand.CreateParameter();
            parameter.ParameterName = "P_DT_DATORD";
            parameter.Direction = ParameterDirection.Input;
            //parameter.DbType = DbType.DateTime;
            //parameter.Value = request.DataOrdem.Value;
            parameter.DbType = DbType.String;
            parameter.Value = request.DataOrdem.Value.ToString("dd/MM/yyyy");
            dbCommand.Parameters.Add(parameter);

            parameter = dbCommand.CreateParameter();
            parameter.ParameterName = "P_NR_SEQORD";
            parameter.Direction = ParameterDirection.Input;
            //parameter.DbType = DbType.Int32;
            //parameter.Value = request.NumeroSequenciaOrdem.Value;
            parameter.DbType = DbType.String;
            parameter.Value = request.NumeroSequenciaOrdem.Value.ToString();
            dbCommand.Parameters.Add(parameter);

            parameter = dbCommand.CreateParameter();
            parameter.ParameterName = "P_NR_SUBSEQ";
            parameter.Direction = ParameterDirection.Input;
            //parameter.DbType = DbType.Int32;
            parameter.DbType = DbType.String;

            if (request.NumeroSubSequenciaOrdem != null)
                parameter.Value = request.NumeroSubSequenciaOrdem.Value.ToString();
            else
                parameter.Value = "0";

            dbCommand.Parameters.Add(parameter);

            parameter = dbCommand.CreateParameter();
            parameter.ParameterName = "P_DT_PREGAO";
            parameter.Direction = ParameterDirection.Input;
            //parameter.DbType = DbType.DateTime;
            //parameter.Value = request.DataPregao.Value;
            parameter.DbType = DbType.String;
            parameter.Value = request.DataPregao.Value.ToString("dd/MM/yyyy");
            dbCommand.Parameters.Add(parameter);

            parameter = dbCommand.CreateParameter();
            parameter.ParameterName = "P_CJO_ANT";
            parameter.Direction = ParameterDirection.Input;
            parameter.DbType = DbType.String;
            parameter.Value = request.NumeroConjunto.Value.ToString();
            
            dbCommand.Parameters.Add(parameter);

            parameter = dbCommand.CreateParameter();
            parameter.ParameterName = "RET";
            parameter.Direction = ParameterDirection.ReturnValue;
            parameter.DbType = DbType.Int32;
            parameter.Value = null;
            parameter.Size = 6;
            dbCommand.Parameters.Add(parameter);
            #endregion Cria os Parametros a Adiciona ao Command

            this.DataBase.ExecuteScalar(dbCommand);
            return Convert.ToInt32(parameter.Value);
        }

        ///<summary>
        ///Método responsável por criar um novo lote para ordens que ainda 
        ///não possuam lotes associados (NumeroConjunto = zero).
        ///</summary>
        ///<returns>Número do novo lote recém-criado.</returns>
        // Marcelo Barucci  11/07/2008        Criacao  
        // WAbreu.7COMm     02/10/2008 11:00  Revisao. Retorna numero do novo lote.
        public int CriarLoteOrdemSemLote(List<BusinessEntity.LoteOrdem> request)
        {
            //Recupera o Numero sequencial para o Lote
            Int32 numeroLote = RecuperaProximoNumeroLote() + 1;

            foreach (BusinessEntity.LoteOrdem item in request)
            {
                item.NumeroConjunto = numeroLote;
                DbCommand dbCommand;
                StringBuilder sql = new StringBuilder();

                sql.Append("INSERT INTO TORDISCONJ ( ");
                sql.Append("   DT_DATORD, ");
                sql.Append("   NR_SEQORD, ");
                sql.Append("   NR_SUBSEQ, ");
                sql.Append("   DT_PREGAO, ");
                sql.Append("   NR_CONJUNTO, ");
                sql.Append("   DT_SISTEMA ");
                sql.Append(") VALUES ( ");
                sql.Append(" :P_DT_DATORD, ");
                sql.Append(" :P_NR_SEQORD, ");
                sql.Append(" :P_NR_SUBSEQ, ");
                sql.Append(" :P_DT_PREGAO, ");
                sql.Append(" :P_NR_CONJUNTO, ");
                sql.Append(" SYSDATE ");
                sql.Append(") ");

                dbCommand = this.DataBase.GetSqlStringCommand(sql.ToString());

                this.DataBase.AddInParameter(dbCommand, "P_DT_DATORD", DbType.DateTime, item.DataOrdem.Value);
                this.DataBase.AddInParameter(dbCommand, "P_NR_SEQORD", DbType.Int32, item.NumeroSequenciaOrdem.Value);
                this.DataBase.AddInParameter(dbCommand, "P_NR_SUBSEQ", DbType.Int32, item.NumeroSubSequenciaOrdem.Value);
                this.DataBase.AddInParameter(dbCommand, "P_DT_PREGAO", DbType.DateTime, item.DataPregao.Value);
                this.DataBase.AddInParameter(dbCommand, "P_NR_CONJUNTO", DbType.Int32, numeroLote);

                this.DataBase.ExecuteNonQuery(dbCommand);
            }

            return  numeroLote;
        }

        /// <summary>
        /// Data:14/07/2008
        /// Autor:Marcelo Barucci
        /// Obs:
        /// Metodo responsavel por Alterar o Numero do Conjunto Lote Ordem 
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool TrocarOrdemLote(List<BusinessEntity.LoteOrdem> request)
        {
            return (TrocarOrdemLote(request, 0));
        }

        /// <summary>
        /// Data:14/07/2008
        /// Autor:Marcelo Barucci
        /// Obs:
        /// Metodo responsavel por Alterar o Numero do Conjunto Lote Ordem 
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool TrocarOrdemLote(List<BusinessEntity.LoteOrdem> request, Int32 numeroLoteDestino)
        {
            ///Implementar o tratamento de erros adequado.
            if (request == null || request.Count == 0)
                throw new Exception();

            foreach (BusinessEntity.LoteOrdem loteOrdem in request)
            {
                if (numeroLoteDestino != 0)
                    loteOrdem.NumeroConjuntoDestino = numeroLoteDestino;

                DbCommand dbCommand;
                DbParameter parameter;
                StringBuilder sql = new StringBuilder();

                /*
                 PROCEDURE TROCA_CONJ (P_DT_DATORD VARCHAR2, P_NR_SEQORD VARCHAR2, P_NR_SUBSEQ VARCHAR2,
                    P_DT_PREGAO VARCHAR2, P_CJO_ANT   VARCHAR2, P_CJO_ATU   VARCHAR2);                 
                */
                sql.Append("BEGIN ");
                sql.Append("ATUA_CONJORD.TROCA_CONJ(:P_DT_DATORD,:P_NR_SEQORD,:P_NR_SUBSEQ,:P_DT_PREGAO,:P_CJO_ANT,:P_CJO_ATU);");
                sql.Append("END; ");
                dbCommand = this.DataBase.GetSqlStringCommand(sql.ToString());

                #region Cria os Parametros a Adiciona ao Command
                parameter = dbCommand.CreateParameter();
                parameter.ParameterName = "P_DT_DATORD";
                parameter.Direction = ParameterDirection.Input;
                //parameter.DbType = DbType.DateTime;
                //parameter.Value = loteOrdem.DataOrdem.Value;
                parameter.DbType = DbType.String;
                parameter.Value = loteOrdem.DataOrdem.Value.ToString("dd/MM/yyyy");
                dbCommand.Parameters.Add(parameter);

                parameter = dbCommand.CreateParameter();
                parameter.ParameterName = "P_NR_SEQORD";
                parameter.Direction = ParameterDirection.Input;
                //parameter.DbType = DbType.Int32;
                //parameter.Value = loteOrdem.NumeroSequenciaOrdem.Value;
                parameter.DbType = DbType.String;
                parameter.Value = loteOrdem.NumeroSequenciaOrdem.Value.ToString();
                dbCommand.Parameters.Add(parameter);

                parameter = dbCommand.CreateParameter();
                parameter.ParameterName = "P_NR_SUBSEQ";
                parameter.Direction = ParameterDirection.Input;
                //parameter.DbType = DbType.Int32;                
                //parameter.Value = loteOrdem.NumeroSubSequenciaOrdem.Value;
                parameter.DbType = DbType.String;

                if (loteOrdem.NumeroSubSequenciaOrdem != null)
                    parameter.Value = loteOrdem.NumeroSubSequenciaOrdem.Value.ToString();
                else
                    parameter.Value = "0";

                dbCommand.Parameters.Add(parameter);

                parameter = dbCommand.CreateParameter();
                parameter.ParameterName = "P_DT_PREGAO";
                parameter.Direction = ParameterDirection.Input;
                //parameter.DbType = DbType.DateTime;
                //parameter.Value = loteOrdem.DataPregao.Value;
                parameter.DbType = DbType.String;
                parameter.Value = loteOrdem.DataPregao.Value.ToString("dd/MM/yyyy");
                dbCommand.Parameters.Add(parameter);

                parameter = dbCommand.CreateParameter();
                parameter.ParameterName = "P_CJO_ANT";
                parameter.Direction = ParameterDirection.Input;
                parameter.DbType = DbType.String;
                parameter.Value = loteOrdem.NumeroConjunto.Value.ToString();
                dbCommand.Parameters.Add(parameter);

                parameter = dbCommand.CreateParameter();
                parameter.ParameterName = "P_CJO_ATU";
                parameter.Direction = ParameterDirection.Input;
                parameter.DbType = DbType.String;
                parameter.Value = loteOrdem.NumeroConjuntoDestino.Value.ToString();
                dbCommand.Parameters.Add(parameter);
                #endregion Cria os Parametros a Adiciona ao Command

                this.DataBase.ExecuteNonQuery(dbCommand);
            }
            return true;
        }

        public List<BusinessEntity.LoteOrdem> ConsultarLoteVinculado(
            BusinessEntity.Parameter.ConsultarLoteVinculadoParameter pRequest
        )
        {
            DbCommand cmd;
            StringBuilder sql = new StringBuilder();

            #region Montar a cláusula SQL

            sql.AppendLine(@"
                select b.nr_conjunto NumeroConjunto, 
                       ROUND(NVL(sum( c.qt_negocio * c.vl_medio / c.ft_valorizacao ) / sum( c.qt_negocio ), 0), 6) PrecoMedio, 
                       TO_CHAR(b.NR_CONJUNTO) NomeLote,
                       nvl( sum( c.qt_negocio ), 0 ) QuantidadeCasada
                  from tordisconj b,
                       tormovd a,
                       ( select aa.dt_datord, aa.nr_seqord, aa.nr_subseq, 
                                sum( trunc( aa.qt_negocio * aa.vl_negocio / bb.ft_valorizacao, 2 ) ) / sum( aa.qt_negocio ) vl_medio, 
                                sum( aa.qt_negocio ) qt_negocio, 
                                bb.ft_valorizacao,
                                bb.tp_mercado 
                           from torexec aa, tornegd bb
                          where aa.dt_negocio  = :pDataPregao
                            and aa.cd_natope   = :pNatOp
                            and bb.cd_codcas   = :pCodCasa
                            and bb.dt_pregao   = aa.dt_negocio 
                            and bb.cd_bolsamov = aa.cd_bolsamov 
                            and bb.nr_negocio  = aa.nr_negocio 
                            and bb.cd_negocio  = aa.cd_negocio 
                            and bb.cd_natope   = aa.cd_natope 
                          group by aa.dt_datord, aa.nr_seqord, aa.nr_subseq, bb.ft_valorizacao,bb.tp_mercado ) c,
                       ( select distinct
                                nvl( ll.cod_brkr_intm, ii.cd_cliente ) cod_brkr_intm, ii.nm_apelido
                           from tborelc_brkr rr,
                                tscclibol ii,
                                ( select cod_brkr_intm, cod_brkr_prin
                                    from tborelc_brkr
                                   union
                                  select cod_brkr_prin, cod_brkr_prin
                                    from tborelc_brkr ) ll
                          where ii.cd_cliente = ll.cod_brkr_prin(+)");

            if (pRequest.CodigoCliente == null)
                sql.AppendLine(@"                    
                    and ii.nm_apelido = :pApelido                
                ");
            else
                sql.AppendLine(@"and ii.cd_cliente = :pCodClie ");

            sql.AppendLine(@") d
                 where c.dt_datord  = b.dt_datord 
                   and c.nr_seqord  = b.nr_seqord 
                   and c.nr_subseq  = b.nr_subseq 
                   and b.dt_pregao  = :pDataPregao
                   and a.dt_datord  = c.dt_datord
                   and a.nr_seqord  = c.nr_seqord
                   and a.nr_subseq  = c.nr_subseq
                   and a.cd_cliente = d.cod_brkr_intm
                   and a.cd_natope  = :pNatOp
                   and decode( c.tp_mercado, 'FRA', 'VIS', c.tp_mercado ) = decode( a.cd_mercad, 'FRA', 'VIS', a.cd_mercad )");

            if (pRequest.Discricionaria == "S")
                sql.AppendLine("and sign( instr( to_char( a.tp_ordem ), '4' ) ) = 1");
            else
                sql.AppendLine("and sign( instr( to_char( a.tp_ordem ), '4' ) ) = 0");

            if (pRequest.PrazoTermo != null )
                sql.AppendLine(@"and a.tp_vcoter = :PrazoTermo");

            sql.AppendLine(@"group by b.nr_conjunto");

            cmd = this.DataBase.GetSqlStringCommand(sql.ToString());

            this.DataBase.AddInParameter(cmd, "pDataPregao", DbType.DateTime, pRequest.DataPregao);
            this.DataBase.AddInParameter(cmd, "pNatOp", DbType.String, pRequest.NaturezaOperacao == BusinessEntity.Enum.TipoNaturezaOperacao.Compra ? "C" : "V" );
            this.DataBase.AddInParameter(cmd, "pCodCasa", DbType.String, pRequest.CodigoCasamento);

            if (pRequest.CodigoCliente == null)
                this.DataBase.AddInParameter(cmd, "pApelido", DbType.String, pRequest.ApelidoCliente);
            else
                this.DataBase.AddInParameter(cmd, "pCodClie", DbType.Int32, pRequest.CodigoCliente);

            if (pRequest.PrazoTermo != null)
                this.DataBase.AddInParameter(cmd, "PrazoTermo", DbType.Int32, pRequest.PrazoTermo);
            #endregion

            #region Obter os registros e montar a List<> com os resultados
            IDataReader reader = this.DataBase.ExecuteReader(cmd);

            List<BusinessEntity.LoteOrdem> response = new List<BusinessEntity.LoteOrdem>();

            while (reader.Read())
            {
                BusinessEntity.LoteOrdem loteOrdem = new BusinessEntity.LoteOrdem();
                loteOrdem.NumeroConjunto = Convert.ToInt32(reader["NumeroConjunto"].ToString());
                loteOrdem.PrecoMedio = Convert.ToDecimal(reader["PrecoMedio"].ToString());
                loteOrdem.NomeLote = reader["NomeLote"].ToString();
                loteOrdem.QuantidadeCasada = reader.GetValue<decimal?>("QuantidadeCasada");
                response.Add(loteOrdem);
            }

            reader.Close();
            #endregion

            return response;
        }

        #region Métodos auxiliares da classe
        /// <summary>
        /// Data:11/07/2008
        /// Autor:Marcelo Barucci
        /// Obs:
        /// Método utilizado para recuperar o numero do lote.
        /// </summary>
        /// <returns>Int32 Número do Lote</returns>
        private Int32 RecuperaProximoNumeroLote()
        {
            Int32 auxNumeroAtualDoLote;
            StringBuilder sql = new StringBuilder();
            sql.AppendLine(" SELECT NR_CONJUNTO FROM TORSEQCJO");
            DbCommand dbCommand = this.DataBase.GetSqlStringCommand(sql.ToString());
            auxNumeroAtualDoLote = Convert.ToInt32(this.DataBase.ExecuteScalar(dbCommand));
            IncrementaNumeroLote(auxNumeroAtualDoLote);
            return auxNumeroAtualDoLote;
        }

        /// <summary>
        /// Incrementa 1 ao Numero atual do Lote recuperado.
        /// </summary>
        /// <param name="numeroDoLoteAnterior">Número do lote anterior ou corrente</param>
        private void IncrementaNumeroLote(System.Int32 numeroDoLoteAnterior)
        {
            DbCommand dbCommand;
            StringBuilder sql = new StringBuilder();
            sql.Append(" UPDATE TORSEQCJO SET");
            sql.Append(" TORSEQCJO.NR_CONJUNTO = :NR_CONJUNTONOVO");
            sql.Append(" WHERE TORSEQCJO.NR_CONJUNTO = :NR_CONJUNTO");
            dbCommand = this.DataBase.GetSqlStringCommand(sql.ToString());
            this.DataBase.AddInParameter(dbCommand, ":NR_CONJUNTONOVO", DbType.Int32, numeroDoLoteAnterior + 1);
            this.DataBase.AddInParameter(dbCommand, ":NR_CONJUNTO", DbType.Int32, numeroDoLoteAnterior);
            this.DataBase.ExecuteNonQuery(dbCommand);
        }

        #endregion Métodos auxiliares da classe
    }
}
